// jeScriptString based on code of CScriptString - part of angelscript sdk
// (c) jimon game studio

#include <angelscript.h>
#include "jeStl.h"

namespace je
{
	namespace core
	{
		template<class T>
		class jeScriptString
		{
		public:
			static T * StringFactory(asUINT Length,const c8 * Str)
			{
				T * Temp = NULL;
				JENEW(Temp,T(Str,Length))
				return Temp;
			}

			static T * StringDefaultFactory()
			{
				T * Temp = NULL;
				JENEW(Temp,T)
				return Temp;
			}

			static T * StringCopyFactory(const T & Other)
			{
				T * Temp = NULL;
				JENEW(Temp,T(Other))
				return Temp;
			}

			static T * Append(const T & A,const T & B)
			{
				T * Temp = NULL;
				JENEW(Temp,T)
				(*Temp) = A+B;
				return Temp;
			}

			#define JE_PARSERS(__type)\
				static T & Assign##__type##ToString(__type i,T & Destination)\
				{\
					Destination = T(i);\
					return Destination;\
				}\
				static T & AddAssign##__type##ToString(__type i,T & Destination)\
				{\
					Destination += T(i);\
					return Destination;\
				}\
				static T * AddString##__type(const T & Source,__type i)\
				{\
					T * Temp = NULL;\
					JENEW(Temp,T(Source+T(i)))\
					return Temp;\
				}\
				static T * Add##__type##String(__type i,const T & Source)\
				{\
					T * Temp = NULL;\
					JENEW(Temp,T(T(i)+Source))\
					return Temp;\
				}

			JE_PARSERS(f64)
			JE_PARSERS(f32)
			JE_PARSERS(u32)
			JE_PARSERS(s32)
			JE_PARSERS(c8)
			JE_PARSERS(u1)

			static void Register(asIScriptEngine * Engine,const c8 * Name)
			{
				Engine->RegisterObjectType(Name,0,asOBJ_REF);

				Engine->RegisterObjectBehaviour(Name,asBEHAVE_FACTORY,(jeStringc(Name)+jeStringc(" @f()")).c_str(),asFUNCTION(StringDefaultFactory),asCALL_CDECL);
				Engine->RegisterObjectBehaviour(Name,asBEHAVE_FACTORY,(jeStringc(Name)+jeStringc(" @f(const ")+jeStringc(Name)+jeStringc(" &in)")).c_str(),asFUNCTION(StringCopyFactory),asCALL_CDECL);
				Engine->RegisterObjectBehaviour(Name,asBEHAVE_ADDREF,"void f()",asMETHOD(T,Grab),asCALL_THISCALL);
				Engine->RegisterObjectBehaviour(Name,asBEHAVE_RELEASE,"void f()",asMETHOD(T,Drop),asCALL_THISCALL);
				Engine->RegisterObjectMethod(Name,(jeStringc(Name)+jeStringc(" &opAssign(const ")+jeStringc(Name)+jeStringc(" &in)")).c_str(),asMETHODPR(T,operator=,(const T&),T&),asCALL_THISCALL);
				Engine->RegisterObjectMethod(Name,(jeStringc(Name)+jeStringc(" &opAddAssign(const ")+jeStringc(Name)+jeStringc(" &in)")).c_str(),asMETHODPR(T,operator+=,(const T&),T&),asCALL_THISCALL);

				Engine->RegisterObjectMethod(Name,(jeStringc("bool opEquals(const ")+jeStringc(Name)+jeStringc(" &in) const")).c_str(),asMETHODPR(T,operator==,(const T&) const,u1),asCALL_THISCALL);
				Engine->RegisterObjectMethod(Name,(jeStringc(Name)+jeStringc("@ opAdd(const ")+jeStringc(Name)+jeStringc(" &in) const")).c_str(),asFUNCTION(Append),asCALL_CDECL_OBJFIRST);

				Engine->RegisterObjectMethod(Name,"uint GetSize() const",asMETHOD(T,GetSize),asCALL_THISCALL);

				#define JE_PARSERS2(__type,__name)\
					Engine->RegisterObjectMethod(Name,(jeStringc(Name)+jeStringc("& opAssign("#__name")")).c_str(),asFUNCTION(Assign##__type##ToString),asCALL_CDECL_OBJLAST);\
					Engine->RegisterObjectMethod(Name,(jeStringc(Name)+jeStringc("& opAssign(const "#__name")")).c_str(),asFUNCTION(Assign##__type##ToString),asCALL_CDECL_OBJLAST);\
					Engine->RegisterObjectMethod(Name,(jeStringc(Name)+jeStringc("& opAddAssign("#__name")")).c_str(),asFUNCTION(AddAssign##__type##ToString),asCALL_CDECL_OBJLAST);\
					Engine->RegisterObjectMethod(Name,(jeStringc(Name)+jeStringc("& opAddAssign(const "#__name")")).c_str(),asFUNCTION(AddAssign##__type##ToString),asCALL_CDECL_OBJLAST);\
					Engine->RegisterObjectMethod(Name,(jeStringc(Name)+jeStringc("@ opAdd("#__name") const")).c_str(),asFUNCTION(AddString##__type),asCALL_CDECL_OBJFIRST);\
					Engine->RegisterObjectMethod(Name,(jeStringc(Name)+jeStringc("@ opAdd(const "#__name") const")).c_str(),asFUNCTION(AddString##__type),asCALL_CDECL_OBJFIRST);\
					Engine->RegisterObjectMethod(Name,(jeStringc(Name)+jeStringc("@ opAdd_r("#__name") const")).c_str(),asFUNCTION(Add##__type##String),asCALL_CDECL_OBJLAST);\
					Engine->RegisterObjectMethod(Name,(jeStringc(Name)+jeStringc("@ opAdd_r(const "#__name") const")).c_str(),asFUNCTION(Add##__type##String),asCALL_CDECL_OBJLAST);

				JE_PARSERS2(f64,double)
				JE_PARSERS2(f32,float)
				JE_PARSERS2(u32,uint)
				JE_PARSERS2(s32,int)
				JE_PARSERS2(c8,int8)
				JE_PARSERS2(u1,bool)
			}
		};

		typedef jeScriptString<jeStringc> jeScriptStringc;
		typedef jeScriptString<jeStringw> jeScriptStringw;

		void RegisterJeScriptString(asIScriptEngine * Engine)
		{
			jeScriptStringc::Register(Engine,"stringc");
			jeScriptStringw::Register(Engine,"stringw");

			Engine->RegisterStringFactory("stringc@",asFUNCTION(jeScriptStringc::StringFactory),asCALL_CDECL);
		}
	}
}
